package com.scs.application.core.thread;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.utils.excel.ImportExcel;
import org.apache.http.util.Asserts;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.ValidationException;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.RecursiveAction;

/**
 * @Description: BatchSaveTask
 **/
public class BatchSaveTask<E> extends RecursiveAction {

    private BatchSaveHandler<E> handler;

    private List<E> list;

    private int batchSize;

    private int beginIndex;

    private int endIndex;

    private static final int DEFAULT_BATCH_SIZE = 200;

    public BatchSaveTask(MultipartFile file, Class<E> dtoClass, BatchSaveHandler<E> handler) throws IOException, InvalidFormatException, IllegalAccessException, InstantiationException, org.apache.poi.openxml4j.exceptions.InvalidFormatException {
        this(file, dtoClass, handler, DEFAULT_BATCH_SIZE);
    }

    public BatchSaveTask(MultipartFile file, Class<E> dtoClass, BatchSaveHandler<E> handler, int batchSize) throws IOException, InvalidFormatException, IllegalAccessException, InstantiationException, org.apache.poi.openxml4j.exceptions.InvalidFormatException {
        ImportExcel ei = new ImportExcel(file, 1, 0);
        List<E> dtoList = ei.getDataList(dtoClass);
        this.handler = handler;
        this.list = dtoList;
        this.batchSize = batchSize;
        this.beginIndex = 0;
        this.endIndex = dtoList.size();
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }
    }

    public BatchSaveTask(BatchSaveHandler<E> handler, List<E> list, int batchSize) {
        this(handler, list, batchSize, 0, list.size());
    }

    public BatchSaveTask(BatchSaveHandler<E> handler, List<E> list) {
        this(handler, list, DEFAULT_BATCH_SIZE, 0, list.size());
    }

    /**
     * @param handler
     * @param list
     * @param batchSize
     */
    public BatchSaveTask(BatchSaveHandler<E> handler, List<E> list, int batchSize, int beginIndex, int endIndex) {
        Asserts.notNull(handler, "handler must be not null");
        Asserts.notNull(list, "list must be not null");

        this.handler = handler;
        this.list = list;
        this.batchSize = batchSize;
        this.beginIndex = beginIndex;
        this.endIndex = endIndex;
    }


    @Override
    protected void compute() {

        int size = list.size();

        if (size <= batchSize) {
            for (int i = 0; i < list.size(); i++) {
                int currentIndex = beginIndex + i;

                E entity = list.get(i);
                try {
                    this.handler.doValidate(currentIndex + 1, entity);

                    this.handler.doSave(currentIndex + 1, entity);

                    this.handler.onSaveSuccess(currentIndex + 1, entity);
                } catch (ValidationException e) {
                    this.handler.onValidateError(currentIndex + 1, entity, e);
                } catch (BusinessException e) {
                    this.handler.onSaveError(currentIndex + 1, entity, e);
                }
            }
            return;
        }

        int middle = size / 2;
        BatchSaveTask left = new BatchSaveTask(this.handler, list.subList(0, middle), batchSize, beginIndex, beginIndex + middle);
        BatchSaveTask right = new BatchSaveTask(this.handler, list.subList(middle, size), batchSize, beginIndex + middle, beginIndex + size);

        //执行子任务
        left.fork();
        right.fork();

        //获取子任务结果
        left.join();
        right.join();

    }

    public List<E> getList() {
        return Collections.unmodifiableList(this.list);
    }

    public BatchSaveHandler<E> getHandler() {
        return this.handler;
    }

}

